package station.Bluetooth;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;

import nxt.commandReference.StationCommands;
import station.GUI.MainForm;


public class BluetoothManager {

	private HashMap<RemoteDevice, String> availableDevices = new HashMap<RemoteDevice, String>();
	private LocalDevice localDevice;
	//private RemoteDevice _NXT;
	private StreamConnection _NXTConnection;
	private DataInputStream _NXTInput;
	private DataOutputStream _NXTOutput;
	//private RemoteDevice _Camera;
	//private StreamConnection _CameraConnection;
	
	private NXTListingThread _NXTListingThread;
	private MainForm _GUIMainForm;

	public BluetoothManager() {
	}

	public boolean isConnectedToNXT(){
		return (_NXTConnection == null)?false:true;
	}
	
	public void refreshDevices() {
		System.out.println("Bluetoothrefresh Started");
		availableDevices.clear();
		try {
			localDevice = LocalDevice.getLocalDevice();
			DiscoveryAgent agent = localDevice.getDiscoveryAgent();
			final Object lock = new Object();

			agent.startInquiry(DiscoveryAgent.GIAC, new DiscoveryListener() {

				@Override
				public void inquiryCompleted(int arg0) {
					// TODO Auto-generated method stub
					System.out.println("Fired Complet inquiry");
					synchronized (lock) {
						lock.notify();
					}
				}

				@Override
				public void deviceDiscovered(RemoteDevice arg0, DeviceClass arg1) {
					// TODO Auto-generated method stub
					if (!availableDevices.containsKey(arg0)) {
						try {
							String name = arg0.getFriendlyName(true);
							String address = arg0.getBluetoothAddress();
							System.out.println("Device '" + name + "' found with address '" + address + "'");
							availableDevices.put(arg0, name);
						} catch (IOException e) {
							e.printStackTrace();
							System.out.println("Error while firing deviceDiscovered!");
						}
					}
				}

				@Override
				public void serviceSearchCompleted(int arg0, int arg1) {
					// TODO Auto-generated method stub

				}

				@Override
				public void servicesDiscovered(int arg0, ServiceRecord[] arg1) {
					// TODO Auto-generated method stub

				}
			});

			synchronized (lock) {
				lock.wait();
			}

		} catch (BluetoothStateException btsE) {
			btsE.printStackTrace();
			System.out.println("Error with BluetoothState!");
		} catch (InterruptedException e) {
			e.printStackTrace();
			System.out.println("Error while refreshing devices");
		}
	}

	public boolean devicesFound() {
		return availableDevices.isEmpty();
	}

	public Collection<String> getDeviceNames() {
		return availableDevices.values();
	}
		
	public boolean connectNXTTo(String deviceName){
		try {
			for(Entry<RemoteDevice, String> e : availableDevices.entrySet()){
				if(e.getValue().equals(deviceName)){
					_NXTListingThread = new NXTListingThread();
					_NXTListingThread.setMainForm(_GUIMainForm);
					_NXTConnection = (StreamConnection) Connector.open("btspp://" + e.getKey().getBluetoothAddress() + ":1;authenticate=false;encrypt=false;master=false");
					//_NXT = e.getKey();
					_NXTInput = _NXTConnection.openDataInputStream();
					_NXTOutput = _NXTConnection.openDataOutputStream();
					
					_NXTListingThread.setNXTInputStream(_NXTInput);
					_NXTListingThread.start();
					return true;
				}
			}
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Error while connecting to NXT!");
			return false;
		}
	}
	
	public boolean sendCommandToNXT(byte cmd){
		try {
			_NXTOutput.write(cmd);
			_NXTOutput.flush();
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Error while sending command to NXT!");
			return false;
		}
		return true;
	}
	
	public void disconnectNXT(boolean withCommand){
		try {
			if(withCommand){
				sendCommandToNXT(StationCommands.STATION_DISCONNECTED);
			}
			_NXTListingThread.setShoudStop();
			_NXTInput.close();
			_NXTOutput.close();
			Thread.sleep(100);
			_NXTConnection.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Error while disconnecting from NXT!");
		}
	}

	public void setGUIMainForm(MainForm mainForm) {
		_GUIMainForm = mainForm;
	}
}